//
//  AppAudioManager.swift
//  LeTu
//
//  Created byg1 on 2024/1/15.
//

import AVFoundation
import RxSwift
import AVFoundation
import MediaPlayer

//正在播放回调
//currentTime       播放时间
//currentProgress   播放进度
typealias OnPlayingBlock =  (_ currentTime: Float64,_ currentProgress: Float) -> ()
//准备播放回调
//totalDuration     音频总时长
typealias PrepareToPlayBlock =  (_ totalDuration: Float) -> ()
//正在缓冲回调
//bufferDuration    已缓冲的时长
typealias OnBufferingBlock =  (_ bufferDuration: Float) -> ()
//播放完成回调
//flag              YES播放完成, NO播放失败
typealias CompletePlayingBlock =  (_ flag:Bool, _ currentURLIndex: Int, _ nextPlayModel: ScenicStoryModel?) -> ()
//缓存自动暂停回调, 用于更改播放按钮的样式
//bufferDuration    isPlaying 是否正在播放, 如果没有播放表示正在缓冲
typealias IsPlayingBlock =  (_ isPlaying: Float) -> ()

class AppAudioManager: NSObject {
    
    static let shared = AppAudioManager()
    
    var playingBlock: OnPlayingBlock?
    var prepareToPlayBlock: PrepareToPlayBlock?
    var bufferingBlock: OnBufferingBlock?
    var completePlayBlock: CompletePlayingBlock?
    var isPlayingBlock: IsPlayingBlock?
    
    // AVAsset实例，用于资源加载
    var palyerItem: AVPlayerItem?
    //播放器
    var player: AVPlayer = AVPlayer()
    //播放路径
    private var audioPath: String = ""
    // 播放图片
    private var picUrl: String = ""
    // 播放列表
    private(set) var playlist = [ScenicStoryModel]()
    var currentURLIndex: Int = 0
    var currentStoryModel: ScenicStoryModel? {
        return currentURLIndex < playlist.count ? playlist[currentURLIndex]:nil
    }
    //音量大小
    var volume:Float = 1.0
    // 只有当播放器状态为`ReadyToPlay`，才可以执行拖拽操作，否则crash.
    var canDraggingFlag:Bool = false
    // 是否正在播放
    private(set) var isPlaying: Bool = false
    // 是否连续播放
    var isAutoPlay = false
    //之前播放的进度
    var timeOffset: Float64 = 0
    // 播放速度
    private var desiredRate: Float = 1.0

    var rate: Float {
        get {
            return Float(desiredRate)
        }
        set {
            if player.rate != 0 { 
                player.rate = newValue // 设置新的播放速度
            }
            desiredRate = newValue
        }
    }

    private var nextAction = PublishSubject<Bool>()
    private let disposeBag = DisposeBag()
    
    //播放时间
    var currentTime: Float64 = 0
    //音频总时长
    var totalDuration: Float64 = 0
    var totalDurationText: String {
        return formatTimeFromSeconds(seconds: getTotalDurationBeforePlay() ?? totalDuration)
    }
    // 当前听取权限
    var listenPermission = false
    // 分类下标
    private(set) var currentClassifysIndex = 0
    
    /// 边下边播的代理
    public lazy var resourceLoaderQueue = DispatchQueue(label: "LT_resourceLoaderQueue")
    // 是否启用缓存功能
    var cacheEnabled: Bool = true
    // 用于缓存音频数据的字典
    private var audioDataCache: [URL: Data] = [:]
    
    override init() {
        super.init()
        
        nextAction.throttle(.milliseconds(500), latest: false, scheduler: MainScheduler.instance).subscribe { value in
            self.playNextAudio(handle: { _ in })
        }.disposed(by: disposeBag)
        
        setupRemoteTransportControls()
    }
    
    // 设置远程控制事件的处理器
    private func setupRemoteTransportControls() {
        let commandCenter = MPRemoteCommandCenter.shared()
        commandCenter.playCommand.addTarget { [weak self] _ in
            self?.playAudio()
            return .success
        }
        commandCenter.pauseCommand.addTarget { [weak self] _ in
            self?.pauseAudio()
            return .success
        }
        commandCenter.nextTrackCommand.addTarget { [weak self] _ in
            self?.playNextAudio(handle: { _ in })
            return .success
        }
        commandCenter.previousTrackCommand.addTarget { [weak self] _ in
            self?.playLastAudio(handle: { _ in })
            return .success
        }
    }
    
    // 更新锁屏界面的音频信息
    private func updateNowPlayingInfo() {
        guard currentURLIndex >= 0 && currentURLIndex < playlist.count else { return }
        guard let currentItem = player.currentItem else { return }
        guard let asset = currentItem.asset as? AVURLAsset else { return }
        let item = playlist[currentURLIndex]
        var nowPlayingInfo: [String: Any] = [:]
        let artwork: MPMediaItemArtwork
        
        if let image = SDImageCache.shared.imageFromCache(forKey: picUrl) {
            artwork = MPMediaItemArtwork(boundsSize: CGSize(width: 300, height: 300)) { _ in
                return image
            }
        } else if let imageURL = URL(string: picUrl), let imageData = try? Data(contentsOf: imageURL), let image = UIImage(data: imageData) {
            artwork = MPMediaItemArtwork(boundsSize: CGSize(width: 300, height: 300)) { _ in
                return image
            }
        } else {
            artwork = MPMediaItemArtwork(boundsSize: CGSize(width: 300, height: 300)) { _ in
                // 返回默认图片
                return UIImage(named: "AppIcon") ?? UIImage()
            }
        }
        
        // 获取已播放的时间
        let elapsedTime = player.currentTime().seconds
        // 将已播放的时间添加到字典中
        nowPlayingInfo[MPNowPlayingInfoPropertyElapsedPlaybackTime] = elapsedTime
        
        // 设置播放总时长
        nowPlayingInfo[MPMediaItemPropertyPlaybackDuration] = asset.duration.seconds
        // 设置音频标题
        nowPlayingInfo[MPMediaItemPropertyTitle] = LanguageManager.shared.currentLanguage == .zh ? item.name:item.englishAudioName
        nowPlayingInfo[MPMediaItemPropertyArtwork] = artwork
        MPNowPlayingInfoCenter.default().nowPlayingInfo = nowPlayingInfo
    }
    
    //MARK:如果在播放音频前有录音操作,需要重新设置音频会话,否则声音极小.
    func setPlaybackSession() {
        let session = AVAudioSession.sharedInstance()
        do {
            try session.setActive(true)
            try session.setCategory(AVAudioSession.Category.playback, mode: .default, options: .allowAirPlay)
        } catch {
            MYLog(error)
        }
    }
    func setPlayList(_ urls: [ScenicStoryModel], currentIndex: Int, listenPermission: Bool) {
        guard urls.count > 0 else { return }
        playlist = urls
        self.listenPermission = listenPermission
        audioPath = LanguageManager.shared.currentLanguage == .zh ? playlist[currentIndex].chineseAudioUrl:playlist[currentIndex].englishAudioUrl
        currentURLIndex = currentIndex
    }
    
    //MARK:创建播放器
    func createAudioPlayer(currentIndex: Int = AppAudioManager.shared.currentURLIndex, pictureUrl: String, currentClassifysIndex: Int) {
        
        self.currentClassifysIndex = currentClassifysIndex
        self.picUrl = pictureUrl
        guard playlist.count > 0 else { return }
        
        if isPlaying {
            pauseAudio()
        }
        
        guard currentIndex < playlist.count else { return }
        audioPath = LanguageManager.shared.currentLanguage == .zh ? playlist[currentIndex].chineseAudioUrl:playlist[currentIndex].englishAudioUrl
        currentURLIndex = currentIndex
        
        guard let url = URL.encodedURL(string: audioPath) else { return }
        var asset: AVURLAsset?
        if cacheEnabled {
            // 创建自定义的AVURLAsset，并设置资源加载器代理为当前实例
            var component = URLComponents(url: url, resolvingAgainstBaseURL: true)!
            component.scheme = "LTStream"
            let streamUrl: URL = component.url!
            asset = AVURLAsset(url: url) // streamUrl)
            asset!.resourceLoader.setDelegate(self, queue: resourceLoaderQueue)
        } else {
            // 如果缓存被禁用，则直接使用普通的AVURLAsset
            asset = AVURLAsset(url: url)
        }
        
        // 检查 AVURLAsset 是否成功创建
        guard let createdAsset = asset else {
            print("Failed to create AVURLAsset.")
            return
        }
        
        // 使用创建的 AVURLAsset 实例创建 AVPlayerItem
        palyerItem = AVPlayerItem(asset: createdAsset)
        //创建ACplayer：负责视频播放
        self.player = AVPlayer.init(playerItem: palyerItem)
        self.player.rate = 1.0
        desiredRate = 1.0
        self.player.volume = self.volume
        
        // 设置属性以允许在外部屏幕激活时播放声音
        player.automaticallyWaitsToMinimizeStalling = false
        player.allowsExternalPlayback = true
        
        // 设置音频会话的类别为播放
        let audioSession = AVAudioSession.sharedInstance()
        do {
            try audioSession.setCategory(.playback, mode: .moviePlayback)
        } catch {
            MYLog("Failed to set audio session category.")
        }
        
        //与播放缓存相关的观测属性
        self.addObserverForPlayItem()
        // 播放完成检测
        addObserverForPlayer()
        isPlaying = true
        
        updateNowPlayingInfo()
        
    }
    
    //MARK:开始播放
    func playAudio() {
        self.player.play()
        rate = desiredRate
        isPlaying = true
        updateNowPlayingInfo()
    }
    
    //MARK:暂停播放
    func pauseAudio() {
        desiredRate = self.player.rate
        self.player.pause()
        isPlaying = false
        updateNowPlayingInfo()
    }
    
    //MARK:停止播放
    func stopAudio() {
        currentURLIndex = 0
        self.destroyPlayer()
        isPlaying = false
    }
    
    //MARK:停止播放
    func restartAudio() {
        picUrl = (LanguageManager.shared.currentLanguage == .zh ? currentStoryModel?.chineseAudioUrl: currentStoryModel?.englishAudioUrl) ?? picUrl
        createAudioPlayer(pictureUrl: picUrl, currentClassifysIndex: currentClassifysIndex)
    }
    
    // MARK: Play lLast URL in Playlist
    func playLastAudio(handle: (Int) -> Void) {
        
        // Increment the index for the next time
        var currentIndex = currentURLIndex-1
        if currentIndex < 0 {
            currentIndex = playlist.count-1
        }
        
        let storyModel = playlist[currentIndex]
        guard listenPermission == true || (listenPermission == false && storyModel.payStatus == 0) else {
            handle(0)
            //playLastAudio()
            return
        }
        currentURLIndex = currentIndex
        
        // Create and play the new audio
        createAudioPlayer(currentIndex: currentURLIndex, pictureUrl: picUrl, currentClassifysIndex: currentClassifysIndex)
        playAudio()
        handle(1)
        
    }
    
    // MARK: Play Next URL in Playlist
    func playNextAudio(handle: (Int) -> Void) {
        
        // Increment the index for the next time
        var currentIndex = currentURLIndex+1
        if currentIndex >= playlist.count {
            currentIndex = 0
        }
        
        let storyModel = playlist[currentIndex]
        guard listenPermission == true || (listenPermission == false && storyModel.payStatus == 0) else {
            handle(0)
            //playNextAudio()
            return
        }
        currentURLIndex = currentIndex
        
        // Create and play the new audio
        createAudioPlayer(currentIndex: currentURLIndex, pictureUrl: picUrl, currentClassifysIndex: currentClassifysIndex)
        playAudio()
        handle(1)
        
    }
    
    // 获取视频总时长
    func getTotalDurationBeforePlay(url: String? = nil) -> TimeInterval? {
        guard let url = URL.encodedURL(string: (url == nil ? self.audioPath:url)!) else {
            return nil
        }
        
        let asset = AVURLAsset(url: url)
        return CMTimeGetSeconds(asset.duration)
    }
    
    //MARK:改变播放进度
    func changeAudio(currentTime:Float64) {
        let time: CMTime = CMTimeMakeWithSeconds(currentTime, preferredTimescale: 1 * Int32(NSEC_PER_SEC))
        self.player.seek(to: time, toleranceBefore: CMTime.zero, toleranceAfter:CMTime.zero)
        sleep(1)
        updateNowPlayingInfo()
    }
    
    //MARK:Notification
    //播放完毕
    func addObserverForPlayer() {
        NotificationCenter.default.addObserver(self, selector: #selector(audioPlayCompletion), name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: nil)
    }
    
    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        let playerItem:AVPlayerItem = object as! AVPlayerItem
        
        if keyPath == "status" {
            switch self.palyerItem?.status {
            case .readyToPlay ://准备播放
                self.canDraggingFlag = true
                
                self.totalDuration = CMTimeGetSeconds(playerItem.duration)
                self.prepareToPlayBlock?(Float(self.totalDuration))
                
                if self.timeOffset>0 {
                    let time:CMTime = CMTimeMakeWithSeconds(self.timeOffset, preferredTimescale: 1 * Int32(NSEC_PER_SEC))
                    self.player.seek(to: time, toleranceBefore: CMTime.zero, toleranceAfter:CMTime.zero)
                }
                self.updatePlayProgress()//播放进度
                
                //self.playAudio()
                break
            case .failed:
                self.completePlayBlock?(false, currentURLIndex, nil)
                break
            case .unknown:
                break
            default :
                break
            }
        } else if keyPath == "loadedTimeRanges"{//获取最新缓存的区间
            let bufferInterval:TimeInterval = self.bufferedDuration()
            self.bufferingBlock?(Float(bufferInterval))
        } else if keyPath == "playbackBufferEmpty"{//正在缓存视频请稍等
            
        } else if keyPath == "playbackLikelyToKeepUp"{//缓存好了继续播放
            
        }
    }
    
    //播放进度
    func updatePlayProgress() {
        self.player.addPeriodicTimeObserver(forInterval: CMTimeMake(value: 1, timescale: 1), queue: DispatchQueue.main) { (time) in
            //当前正在播放的时间
            self.currentTime = CMTimeGetSeconds(time)
            self.playingBlock?(self.currentTime,Float(self.currentTime))
        }
    }
    
    //MARK:播放完毕
    @objc func audioPlayCompletion() {
        if self.player.currentItem?.status == AVPlayerItem.Status.readyToPlay {
            self.player.seek(to: CMTime.zero) { finished in
                let oldIndex = self.currentURLIndex
                if self.isAutoPlay {
                    self.nextAction.onNext(true)  // 自动播放下一首
                } else {
                    self.isPlaying = false
                }
                self.updateNowPlayingInfo()
                
//                if self.currentURLIndex < self.playlist.count {
//                    let story = self.playlist[self.currentURLIndex]
//                    apiProvider.request(api: .recordStoryNum(storyId: story.id)) { json, jsonArr, code in
//                        MYLog("AAA - ",json)
//                    }
//                }
                self.completePlayBlock?(true, oldIndex, (self.isAutoPlay ? self.playlist[self.currentURLIndex]:nil))
            }
        }
    }
    
    //MARK:计算缓冲进度
    func bufferedDuration() -> (TimeInterval) {
        let loadTimeArray = self.palyerItem!.loadedTimeRanges
        guard let newTimeRange = loadTimeArray.first as? CMTimeRange else {
            return (0)
        }
        //获取最新缓存的区间
        let startSeconds = CMTimeGetSeconds(newTimeRange.start);
        let durationSeconds = CMTimeGetSeconds(newTimeRange.duration);
        let totalBuffer = startSeconds + durationSeconds;//缓冲总长度
        //MYLog("当前缓冲时间：\(totalBuffer)")
        return totalBuffer
    }
    
    //MARK:释放 播放器
    func destroyPlayer() {
        
        isPlaying = false
        
        isAutoPlay = false
        
        // 移除观察者
        removeObserverFromPlayer()
        
        self.player.pause()
        self.currentTime = 0.0
        self.player.currentItem?.cancelPendingSeeks()
        self.player.currentItem?.asset.cancelLoading()
        self.player.replaceCurrentItem(with: nil)
    }
    
    //MARK:Observer
    //观察 加载状态 加载进度
    func addObserverForPlayItem() {
        self.player.currentItem?.addObserver(self, forKeyPath: "status", options: .new, context: nil)
        self.player.currentItem?.addObserver(self, forKeyPath: "loadedTimeRanges", options: .new, context: nil)
        self.player.currentItem?.addObserver(self, forKeyPath: "playbackBufferEmpty", options: .new, context: nil)
        self.player.currentItem?.addObserver(self, forKeyPath: "playbackLikelyToKeepUp", options: .new, context: nil)
    }
    
    
    //MARK:移除通知
    func removeObserverFromPlayer() {
        
        self.player.currentItem?.removeObserver(self, forKeyPath: "status")
        self.player.currentItem?.removeObserver(self, forKeyPath: "loadedTimeRanges")
        self.player.currentItem?.removeObserver(self, forKeyPath: "playbackBufferEmpty")
        self.player.currentItem?.removeObserver(self, forKeyPath: "playbackLikelyToKeepUp")
        
        NotificationCenter.default.removeObserver(self, name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: nil)
    }
    
    // 清空初始状态
    func resetInitState() {
        // 重置自动播放状态
        isAutoPlay = false
        playlist = []
        // 清空player
        stopAudio()
        // 清空锁屏界面的音频信息
        MPNowPlayingInfoCenter.default().nowPlayingInfo = [:]
    }
    
}

extension AppAudioManager {
    
    func formatTimeFromSeconds(seconds: Double) -> String {
        let formatter = DateComponentsFormatter()
        
        if seconds < 3600 {
            // 如果秒数小于1小时，则只显示分钟和秒
            formatter.unitsStyle = .positional
            formatter.allowedUnits = [.minute, .second]
        } else {
            // 如果秒数大于等于1小时，则显示小时、分钟和秒
            formatter.unitsStyle = .positional
            formatter.allowedUnits = [.hour, .minute, .second]
        }
        
        formatter.zeroFormattingBehavior = .pad
        
        return formatter.string(from: TimeInterval(seconds)) ?? "00:00"
    }
    
}

// MARK: - 处理缓存
extension AppAudioManager: AVAssetResourceLoaderDelegate {
    
    // 实现AVAssetResourceLoaderDelegate协议的方法，用于加载音频数据并进行缓存
    func resourceLoader(_ resourceLoader: AVAssetResourceLoader, didCancel authenticationChallenge: URLAuthenticationChallenge) {
        print("")
    }
    func resourceLoader(_ resourceLoader: AVAssetResourceLoader, shouldWaitForLoadingOfRequestedResource loadingRequest: AVAssetResourceLoadingRequest) -> Bool {
//        guard let url = loadingRequest.request.url else {
//            return false
//        }
//        
//        // 检查是否启用缓存功能
//        guard cacheEnabled else {
//            // 如果缓存功能被禁用，则直接加载音频数据，不进行缓存
//            loadAudioData(for: loadingRequest)
//            return true
//        }
//        
//        // 检查缓存中是否已经有了该音频数据
//        if let cachedData = audioDataCache[url] {
//            // 如果缓存中有数据，则直接响应加载请求
//            respondWithCachedData(cachedData, for: loadingRequest)
//            return true
//        }
//        
//        // 如果缓存中没有数据，则开始加载音频数据
//        loadAudioData(for: loadingRequest)
        
        return true
    }
    
    // 加载音频数据并进行缓存
    private func loadAudioData(for loadingRequest: AVAssetResourceLoadingRequest) {
        guard let url = loadingRequest.request.url else {
            return
        }
        
        let task = URLSession.shared.dataTask(with: url) { [weak self] (data, response, error) in
            guard let data = data, error == nil else {
                return
            }
            
            // 缓存加载的音频数据
            self?.audioDataCache[url] = data
            
            // 响应加载请求
            self?.respondWithCachedData(data, for: loadingRequest)
        }
        
        task.resume()
    }
    
    // 响应加载请求，并提供缓存的音频数据
    private func respondWithCachedData(_ data: Data, for loadingRequest: AVAssetResourceLoadingRequest) {
        guard let contentInformationRequest = loadingRequest.contentInformationRequest else {
            return
        }
        
        // 设置音频数据的MIME类型和大小
        contentInformationRequest.contentType = "audio/mpeg"
        contentInformationRequest.contentLength = Int64(data.count)
        
        // 响应请求，提供缓存的音频数据
        loadingRequest.dataRequest?.respond(with: data)
        
        // 完成加载请求
        loadingRequest.finishLoading()
    }
        
    
}


